package org.market.domain.strategy.service.armory;

import lombok.extern.slf4j.Slf4j;
import org.market.domain.strategy.model.entity.StrategyAwardEntity;
import org.market.domain.strategy.model.entity.StrategyEntity;
import org.market.domain.strategy.model.entity.StrategyRuleEntity;
import org.market.domain.strategy.repository.IStrategyRepository;
import org.market.types.common.Constants;
import org.market.types.enums.ResponseCode;
import org.market.types.exception.AppException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.util.*;

/**
 * @Author: Insight
 * @Description: 策略装配库,负责计算初始策略值
 * @Date: 2025/2/4 下午11:01
 * @Version: 1.0
 */
@Slf4j
@Service
public class StrategyArmoryDispatch implements IStrategyArmory,IStrategyDispatch {
    @Resource
    private IStrategyRepository repository;

    /**
     * 完成抽奖策略的装配
     *
     * @param strategyId
     * @return
     */
    @Override
    public boolean assembleLotteryStrategy(Long strategyId) {
        /**查询策略配置*/
        List<StrategyAwardEntity> strategyAwardEntities = repository.queryStrategyAwardList(strategyId);

        assembleStrategyLottery(String.valueOf(strategyId), strategyAwardEntities);

        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
            Integer awardId = strategyAwardEntity.getAwardId();
            Long awardCount = strategyAwardEntity.getAwardCount();
            cacheStrategyAwardCount(strategyId, awardId, awardCount);
        }

        //权重策略配置 --- 适用于rule_weight的权重配置
        StrategyEntity strategyEntities = repository.queryStrategyEntityList(strategyId);
        //查询权重是否存在
        String ruleWeight = strategyEntities.getRuleWeight();
        if (ruleWeight == null) return true;

        //查询策略规则
        StrategyRuleEntity strategyRuleEntity = repository.queryStrategyRuleEntity(strategyId,ruleWeight);

        //校验数据是否为空
        if (strategyRuleEntity == null) {
            throw new AppException(ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getCode(),ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getInfo());
        }

        Map<String, ArrayList<Integer>> ruleWeightValueMap = strategyRuleEntity.getRuleWeightValue();
        Set<String> keys = ruleWeightValueMap.keySet();

        for (String key : keys) {
            List<Integer> ruleModelValue = ruleWeightValueMap.get(key);
            List<StrategyAwardEntity> strategyAwardEntitiesClone = new ArrayList<>(strategyAwardEntities);
            strategyAwardEntitiesClone.removeIf(entity->!ruleModelValue.contains(entity.getAwardId()));
            assembleStrategyLottery(String.valueOf(strategyId).concat("_").concat(key), strategyAwardEntitiesClone);
        }
        return true;
    }

    private void cacheStrategyAwardCount(Long strategyId, Integer awardId, Long awardCount) {
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_KEY + strategyId + Constants.UNDERLINE + awardId;
        repository.cacheStrategyAwardCount(cacheKey,awardCount);
    }

    /**
     * 完成抽奖装配策略
     * @param key
     * @param strategyAwardEntities
     */
    private void assembleStrategyLottery(String key,List<StrategyAwardEntity> strategyAwardEntities) {
        //获取最小概率值
        BigDecimal minAwardRate = strategyAwardEntities.stream().
                map(StrategyAwardEntity::getAwardRate).
                min(BigDecimal::compareTo).
                orElse(BigDecimal.ZERO);
        /**获取概率总和值*/
        BigDecimal awardRateTotal = strategyAwardEntities.stream()
                .map(StrategyAwardEntity::getAwardRate)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        /**获取概率范围(千分位,万分位)*/
        BigDecimal rateRange = awardRateTotal.divide(minAwardRate, 0, RoundingMode.CEILING);

        /**创建每个奖品概率在总概率的占比数组*/
        ArrayList<Integer> strategyAwardSearchRateTable = new ArrayList<>(rateRange.intValue());

        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
            Integer awardId = strategyAwardEntity.getAwardId();
            BigDecimal awardRate = strategyAwardEntity.getAwardRate();
            /**设置每个奖品概率在总概率的占比*/
            for(int i = 0;i < awardRate.multiply(rateRange).setScale(0, RoundingMode.CEILING).intValue();i++){
                strategyAwardSearchRateTable.add(awardId);
            }
        }

        /**打乱顺序*/
        Collections.shuffle(strategyAwardSearchRateTable);

        /**创建map完成一个乱序的表*/
        HashMap<Integer, Integer> shuffleStrategyAwardSearchRateTable = new HashMap<>();

        for (int i = 0; i < strategyAwardSearchRateTable.size(); i++) {
            shuffleStrategyAwardSearchRateTable.put(i,strategyAwardSearchRateTable.get(i));
        }

        /**存储到redis中*/
        repository.storeStrategyAwardSearchRateTable(key,rateRange,shuffleStrategyAwardSearchRateTable);
    }

    /**
     * 通过策略id查概率表获取随机
     * @param strategyId
     * @return
     */
    @Override
    public Integer getRandomAwardId(Long strategyId) {
        int rateRange = repository.getRateRange(strategyId);
        return repository.getStrategyAwardAssemble(String.valueOf(strategyId),new SecureRandom().nextInt(rateRange));
    }



    @Override
    public Integer getRandomAwardId(Long strategyId, String ruleWeightValue) {
        String key = String.valueOf(strategyId).trim().concat("_").concat(ruleWeightValue.trim());
        int rateRange = repository.getRateRange(key);
        return repository.getStrategyAwardAssemble(key,new SecureRandom().nextInt(rateRange));
    }

    @Override
    public Boolean subtractAwardCount(Long strategyId, Integer awardId) {
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_KEY + strategyId + Constants.UNDERLINE + awardId;
        return repository.querySubtractAwardCount(cacheKey);
    }


}
